package cn.lingyangwl.agile.infra.file.utils;

import cn.lingyangwl.agile.common.core.config.GlobalProperties;
import cn.lingyangwl.agile.common.security.utils.SecurityUtils;
import cn.lingyangwl.agile.model.module.auth.LoginUser;
import cn.lingyangwl.framework.core.utils.spring.SpringUtils;
import cn.lingyangwl.framework.tool.core.MD5Utils;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.HtmlUtils;

import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 文件模块工具类
 * @author shenguangyang
 */
@Slf4j
@Component
public class FileUtils {
    private static final List<String> illegalFileStrList = new ArrayList<>();
    private static GlobalProperties properties;

    static {
        illegalFileStrList.add("../");
        illegalFileStrList.add("./");
        illegalFileStrList.add("..\\");
        illegalFileStrList.add(".\\");
        illegalFileStrList.add("\\..");
        illegalFileStrList.add("\\.");
        illegalFileStrList.add("..");
        illegalFileStrList.add("...");
    }

    @PostConstruct
    public void init() {
        FileUtils.properties = SpringUtils.getBean(GlobalProperties.class);
    }

    /**
     * 检查文件名是否合规
     * @param fileName 文件名
     * @return 合规结果,true:不合规，false:合规
     */
    public static boolean isIllegalFileName(String fileName){
        for (String str: illegalFileStrList){
            if(fileName.contains(str)){
                return true;
            }
        }
        return false;
    }

    public static String getFileName(MultipartFile file) {
        // 获取文件名
        String fileName = file.getOriginalFilename();
        //判断是否为IE浏览器的文件名，IE浏览器下文件名会带有盘符信息

        // escaping dangerous characters to prevent XSS
        assert fileName != null;
        fileName = HtmlUtils.htmlEscape(fileName, StandardCharsets.UTF_8.name());

        // Check for Unix-style path
        int unixSep = fileName.lastIndexOf('/');
        // Check for Windows-style path
        int winSep = fileName.lastIndexOf('\\');
        // Cut off at latest possible point
        int pos = (Math.max(winSep, unixSep));
        if (pos != -1) {
            fileName = fileName.substring(pos + 1);
        }
        return fileName;
    }

    /**
     * 生成文件url签名
     */
    public static String genUrlSign(String url) {
        try {
            String path = getObjectNameFormPath(url);
            LoginUser user = SecurityUtils.getLoginUser();
            String data = path + ":" + user.getUserId() + ":" + user.getLoginId() + ":" + properties.getSecretKey();
            return MD5Utils.md5(data);
        } catch (Exception e) {
            log.error("error", e);
            throw new BizException("生成文件地址签名失败");
        }
    }

    public static boolean checkUrlSign(String sign, String url) {
        try {
            String path = getObjectNameFormPath(url);
            LoginUser user = SecurityUtils.getLoginUser();
            String data = path + ":" + user.getUserId() + ":" + user.getLoginId() + ":" + properties.getSecretKey();
            return MD5Utils.md5(data).equals(sign);
        } catch (Exception e) {
            log.error("error", e);
            throw new BizException("校验文件签名失败");
        }
    }

    /**
     * 输入: <a href="http://sw-minio.com:39000/lingyang-boot/image/2023/12/30/1/498837914556485.jpeg">
     *      http://sw-minio.com:39000/lingyang-boot/image/2023/12/30/1/498837914556485.jpeg
     *     </a> <br/>
     * 返回: /image/2023/12/30/1/498837914556485.jpeg
     */
    public static String getObjectNameFormPath(String path) {
        String[] split = path.split("/");
        int length = split.length;
        if (length <= 6) {
            throw new BizException("非法文件路径");
        }
        return split[length - 6] + "/" + split[length - 5] + "/" + split[length - 4] + "/" + split[length - 3] + "/"
            + split[length - 2] + "/" + split[length - 1];
    }

}
